// notifier/dingtalk_app.go
package dingtalk

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"

	// "time"
	"strings"
	"v2/metrics"
	"v2/model"
	// "v2/config"
)

// DingTalkAppNotifier 钉钉应用消息通知器
type DingTalkAppNotifier struct {
	AppKey    string
	AppSecret string
	AgentID   int
	TokenURL  string
	MsgURL    string
}

// NewDingTalkAppNotifier 创建钉钉应用通知器
func NewDingTalkAppNotifier(appKey, appSecret string, agentID int) *DingTalkAppNotifier {
	return &DingTalkAppNotifier{
		AppKey:    appKey,
		AppSecret: appSecret,
		AgentID:   agentID,
		TokenURL:  "https://oapi.dingtalk.com/gettoken",
		MsgURL:    "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2",
	}
}

// getAccessToken 获取 access_token
func (d *DingTalkAppNotifier) getAccessToken() (string, error) {
	resp, err := http.Get(fmt.Sprintf("%s?appkey=%s&appsecret=%s",
		d.TokenURL, d.AppKey, d.AppSecret))
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	var result map[string]interface{}
	json.Unmarshal(body, &result)

	if code, ok := result["errcode"]; ok && code != float64(0) {
		return "", fmt.Errorf("获取 token 失败: %v", result["errmsg"])
	}

	return result["access_token"].(string), nil
}

// getFollowedUsers 获取关注应用的用户列表
func (d *DingTalkAppNotifier) getFollowedUsers(token string) ([]string, error) {
	// 钉钉没有直接获取关注用户列表的API
	// 我们需要获取部门成员，然后筛选出关注了应用的用户
	// 这里简化为获取根部门的所有成员
	deptID := "1" // 根部门ID

	url := fmt.Sprintf("https://oapi.dingtalk.com/topapi/v2/user/list?access_token=%s", token)

	payload := map[string]interface{}{
		"dept_id": deptID,
		"cursor":  0,
		"size":    100,
	}

	jsonData, err := json.Marshal(payload)
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest("POST", url, bytes.NewReader(jsonData))
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	var result map[string]interface{}
	json.Unmarshal(body, &result)

	if code, ok := result["errcode"]; ok && code != float64(0) {
		return nil, fmt.Errorf("获取部门成员失败: %v", result["errmsg"])
	}

	data, ok := result["result"].(map[string]interface{})
	if !ok {
		return nil, fmt.Errorf("解析部门成员数据失败")
	}

	items, ok := data["list"].([]interface{})
	if !ok {
		return []string{}, nil
	}

	var userIds []string
	for _, user := range items {
		userMap, ok := user.(map[string]interface{})
		if !ok {
			continue
		}

		if userid, ok := userMap["userid"].(string); ok && userid != "" {
			userIds = append(userIds, userid)
		}
	}

	return userIds, nil
}

// sendToUser 发送消息给单个用户
func (d *DingTalkAppNotifier) sendToUser(token, userID, content string) error {
	payload := map[string]interface{}{
		"agent_id":    d.AgentID,
		"userid_list": userID,
		"msg": map[string]interface{}{
			"msgtype": "text",
			"text": map[string]string{
				"content": content,
			},
		},
	}

	jsonData, err := json.Marshal(payload)
	if err != nil {
		return err
	}

	req, err := http.NewRequest("POST",
		fmt.Sprintf("%s?access_token=%s", d.MsgURL, token),
		bytes.NewReader(jsonData))
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	var result map[string]interface{}
	json.Unmarshal(body, &result)

	if code, ok := result["errcode"]; ok && code != float64(0) {
		return fmt.Errorf("发送消息失败: %v", result["errmsg"])
	}

	return nil
}

// Send 发送应用消息
func (d *DingTalkAppNotifier) Send(alert model.AlertInfo) error {
	// start := time.Now()

	// 1. 获取 access_token
	token, err := d.getAccessToken()
	if err != nil {
		log.Printf("[DingTalk App] 获取 token 失败: %v", err)
		metrics.AlertSentCounter.WithLabelValues("dingtalk_app", "failure").Inc()
		return err
	}

	// 2. 获取关注应用的用户列表
	userIDs, err := d.getFollowedUsers(token)
	if err != nil {
		log.Printf("[DingTalk App] 获取关注用户列表失败: %v", err)
		metrics.AlertSentCounter.WithLabelValues("dingtalk_app", "failure").Inc()
		return err
	}

	// 如果没有获取到用户ID，直接返回
	if len(userIDs) == 0 {
		log.Printf("[DingTalk App] 没有有效的用户ID，跳过发送")
		return nil
	}

	// 3. 构造消息内容
	content := fmt.Sprintf(
		"%s %s\n\n"+
			"📌 **告警名称**: %s\n"+
			"📍 **所属集群**: %s\n"+
			"🔔 **告警级别**: %s\n"+
			"🕒 **触发时间**: %s\n"+
			"🧮 **触发表达式**: `%s`\n"+
			"📊 **当前值**: %s\n"+
			"👥 **告警分组**: %s",
		alert.EmojiPrefix(),
		"告警",
		alert.RuleName,
		alert.Cluster,
		alert.SeverityText,
		alert.FormattedTime,
		alert.PromQl,
		alert.TriggerValue,
		alert.GroupName,
	)

	for k, v := range alert.TagsMap {
		content += fmt.Sprintf("\n🏷️ `%s`: `%s`", k, v)
	}

	// 4. 遍历所有用户ID，发送消息
	var successCount, failureCount int
	for _, userID := range userIDs {
		err := d.sendToUser(token, userID, content)
		if err != nil {
			// 检查是否是用户未关注错误
			if strings.Contains(err.Error(), "invaliduser") {
				log.Printf("[DingTalk App] 用户 %s 未关注应用", userID)
				failureCount++
			} else {
				log.Printf("[DingTalk App] 发送给用户 %s 失败: %v", userID, err)
				failureCount++
			}
		} else {
			successCount++
		}
	}

	// 5. 更新指标
	total := len(userIDs)
	metrics.AlertSentCounter.WithLabelValues("dingtalk_app", "success").Add(float64(successCount))
	metrics.AlertSentCounter.WithLabelValues("dingtalk_app", "failure").Add(float64(failureCount))
	// metrics.AlertSendDuration.WithLabelValues("dingtalk_app").Observe(time.Since(start).Seconds())

	log.Printf("[DingTalk App] 已发送: %s, 成功: %d/%d", alert.RuleName, successCount, total)
	return nil
}
